package tcpserver.handler;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.util.CharsetUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import utils.sl651.SL651Message;
import utils.sl651.SL651MessageHandlerUtil;
import utils.sl651.SL651MessageValidator;

import java.net.SocketAddress;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * TCP消息处理器
 * 
 * 处理客户端连接、消息接收和发送
 */
public class TcpServerHandler extends ChannelInboundHandlerAdapter {
    
    private static final Logger logger = LoggerFactory.getLogger(TcpServerHandler.class);
    
    private static final AtomicInteger connectionCount = new AtomicInteger(0);
    
    // 分段报文缓存（每个连接一个缓存）
    private StringBuilder messageBuffer = new StringBuilder();
    private long lastMessageTime = 0;
    private static final long MESSAGE_TIMEOUT = 5000; // 5秒超时
    
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        int currentConnections = connectionCount.incrementAndGet();
        SocketAddress remoteAddress = ctx.channel().remoteAddress();
        
        logger.info("新客户端连接: {} | 当前连接数: {}", remoteAddress, currentConnections);
        
        // 发送欢迎消息
        String welcomeMessage = "欢迎连接到RTU TCP服务器！\n";
        ByteBuf welcomeBuf = Unpooled.copiedBuffer(welcomeMessage, CharsetUtil.UTF_8);
        ctx.writeAndFlush(welcomeBuf);
        
        super.channelActive(ctx);
    }
    
    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        int currentConnections = connectionCount.decrementAndGet();
        SocketAddress remoteAddress = ctx.channel().remoteAddress();
        
        logger.info("客户端断开连接: {} | 当前连接数: {}", remoteAddress, currentConnections);
        
        super.channelInactive(ctx);
    }
    
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        ByteBuf byteBuf = (ByteBuf) msg;
        
        try {
            // 读取消息内容
            byte[] bytes = new byte[byteBuf.readableBytes()];
            byteBuf.readBytes(bytes);
            
            String receivedMessage = new String(bytes, CharsetUtil.UTF_8);
            SocketAddress remoteAddress = ctx.channel().remoteAddress();
            
            logger.info("收到来自 {} 的消息: {}", remoteAddress, receivedMessage.trim());
            
            // 处理消息
            String response = processMessage(receivedMessage, ctx);
            
            // 发送响应
            if (response != null && !response.isEmpty()) {
                ByteBuf responseBuf = Unpooled.copiedBuffer(response, CharsetUtil.UTF_8);
                ctx.writeAndFlush(responseBuf);
                logger.info("发送响应到 {}: {}", remoteAddress, response.trim());
            }
            
        } finally {
            // 释放ByteBuf
            byteBuf.release();
        }
    }
    
    /**
     * 处理接收到的消息
     * 
     * @param message 接收到的消息
     * @param ctx Channel上下文
     * @return 响应消息
     */
    private String processMessage(String message, ChannelHandlerContext ctx) {
        String trimmedMessage = message.trim();
        
        // 处理不同类型的消息
        if (trimmedMessage.isEmpty()) {
            return null;
        }
        
        // 心跳消息
        if ("PING".equalsIgnoreCase(trimmedMessage)) {
            return "PONG\n";
        }
        
        // 获取服务器信息
        if ("INFO".equalsIgnoreCase(trimmedMessage)) {
            return String.format("RTU TCP Server - 当前时间: %s | 连接数: %d\n", 
                               new java.util.Date(), connectionCount.get());
        }
        
        // 关闭连接命令
        if ("QUIT".equalsIgnoreCase(trimmedMessage) || "EXIT".equalsIgnoreCase(trimmedMessage)) {
            ctx.writeAndFlush(Unpooled.copiedBuffer("再见！\n", CharsetUtil.UTF_8))
               .addListener(ChannelFutureListener.CLOSE);
            return null;
        }
        
        // 处理分段报文
        String completedMessage = handleFragmentedMessage(trimmedMessage);
        if (completedMessage == null) {
            // 报文仍在缓存中，等待更多数据
            return "部分数据已缓存，等待完整报文...\n";
        }
        
        // 检查是否为SL651协议报文
        String sl651Result = detectSL651Protocol(completedMessage);
        if (sl651Result != null) {
            return sl651Result;
        }
        
        // 默认回显消息
        return "回显: " + completedMessage + "\n";
    }
    
    /**
     * 处理分段报文
     * 
     * @param fragment 报文片段
     * @return 完整报文（如果已完成）或null（如果需要更多数据）
     */
    private String handleFragmentedMessage(String fragment) {
        long currentTime = System.currentTimeMillis();
        
        // 检查是否超时，如果超时则清空缓存
        if (lastMessageTime > 0 && (currentTime - lastMessageTime) > MESSAGE_TIMEOUT) {
            logger.warn("分段报文超时，清空缓存: 长度={}, 内容={}", 
                       messageBuffer.length(), 
                       messageBuffer.substring(0, Math.min(50, messageBuffer.length())));
            messageBuffer.setLength(0);
        }
        
        // 将新片段添加到缓存
        messageBuffer.append(fragment);
        lastMessageTime = currentTime;
        
        String bufferedMessage = messageBuffer.toString();
        String cleanBuffered = bufferedMessage.replaceAll("\\s+", "").toUpperCase();
        
        logger.debug("分段报文处理: 新片段长度={}, 缓存总长度={}, 缓存内容前50字符={}", 
                    fragment.length(), 
                    cleanBuffered.length(), 
                    cleanBuffered.substring(0, Math.min(50, cleanBuffered.length())));
        
        // 先检查当前片段是否本身就是完整报文
        String cleanFragment = fragment.replaceAll("\\s+", "").toUpperCase();
        if (SL651MessageHandlerUtil.isCompleteSL651Message(cleanFragment)) {
            logger.info("单个片段即为完整SL651报文: 长度={}", cleanFragment.length());
            messageBuffer.setLength(0);
            lastMessageTime = 0;
            return cleanFragment;
        }
        
        // 检查缓存中的组合报文是否完整
        if (SL651MessageHandlerUtil.isCompleteSL651Message(cleanBuffered)) {
            // 报文完整，清空缓存并返回
            String completeMessage = cleanBuffered;
            messageBuffer.setLength(0);
            lastMessageTime = 0;
            logger.info("分段SL651报文组装完成: 总长度={}, 片段数=2+", completeMessage.length());
            return completeMessage;
        }
        
        // 检查是否有SL651报文的开始标识
        boolean hasValidStart = cleanBuffered.startsWith("01") || cleanBuffered.startsWith("7E7E");
        if (!hasValidStart && cleanBuffered.length() > 20) {
            // 如果缓存中没有有效的开始标识，且已经积累了足够的数据，则清空缓存
            logger.warn("缓存中无有效SL651开始标识，清空缓存: {}", 
                       cleanBuffered.substring(0, Math.min(20, cleanBuffered.length())));
            messageBuffer.setLength(0);
            lastMessageTime = 0;
            return null;
        }
        
        // 检查缓存是否过大（防止内存溢出）
        if (cleanBuffered.length() > 2000) {
            logger.warn("分段报文缓存过大，强制清空: 长度={}", cleanBuffered.length());
            messageBuffer.setLength(0);
            lastMessageTime = 0;
            return null;
        }
        
        // 报文不完整，继续等待
        logger.debug("分段报文继续等待: 当前缓存长度={}", cleanBuffered.length());
        return null;
    }
    
    /**
     * 检测SL651协议报文类型
     * 根据SL651-2014标准：ASCII编码以01开头，HEX编码以7E7E开头
     * 
     * @param message 原始消息
     * @return 处理结果，如果不是SL651报文则返回null
     */
    private String detectSL651Protocol(String message) {
        // 检测报文格式
        String format = SL651MessageHandlerUtil.detectSL651Protocol(message);
        
        if (format != null) {
            // 清理消息（去除空格和换行符）
            String cleanMessage = message.replaceAll("\\s+", "").toUpperCase();
            return processSL651Message(cleanMessage, format);
        }
        
        return null; // 不是SL651报文
    }
    
    /**
     * 处理SL651协议报文（使用已有的utils解析器）
     * 
     * @param rawMessage 原始报文字符串
     * @param encodingFormat 编码格式（ASCII/HEX/UNKNOWN）
     * @return 处理结果
     */
    private String processSL651Message(String rawMessage, String encodingFormat) {
        try {
            logger.info("处理SL651报文: 格式={}, 长度={}", encodingFormat, rawMessage.length());
            String processedMessage = rawMessage;
            SL651Message message = message = SL651MessageValidator.getMessageInfo(processedMessage);;
            
            if (message.isValid()) {
                // 解析成功
                logger.info("SL651报文解析成功: 原始格式={}, 功能码={}, 站点={}, CRC校验={}", 
                           encodingFormat, 
                           message.getFunctionCode(), 
                           message.getStationAddress(),
                           message.isCrcValid() ? "通过" : "失败");
                
                // 获取解析摘要
                String summary = message.getDataElement("SUMMARY");
                if (summary != null) {
                    logger.info("报文摘要: {}", summary);
                }
                
                // 返回成功响应
                StringBuilder response = new StringBuilder();
                response.append("SL651报文处理成功\n");
                response.append("原始格式: ").append(encodingFormat).append("\n");
                response.append("功能码: ").append(message.getFunctionCode());
               // response.append(" (").append(message.getFunctionCodeDescription()).append(")\n");
                response.append("站点地址: ").append(message.getStationAddress()).append("\n");
                response.append("中心站: ").append(message.getCenterAddress()).append("\n");
                response.append("流水号: ").append(message.getSerialNumber()).append("\n");
                response.append("发报时间: ").append(message.getReportTime()).append("\n");
                response.append("CRC校验: ").append(message.isCrcValid() ? "通过" : "失败").append("\n");
                
                // 添加数据元素信息
                if (message.getDataElements() != null && !message.getDataElements().isEmpty()) {
                    response.append("数据元素: ").append(message.getDataElements().size()).append("个\n");
                    
                    // 显示关键数据元素
                    String rainfall = message.getDataElement("PJ");
                    String waterLevel = message.getDataElement("Z");
                    String voltage = message.getDataElement("VT");
                    
                    if (rainfall != null) response.append("  降水量: ").append(rainfall).append("mm\n");
                    if (waterLevel != null) response.append("  水位: ").append(waterLevel).append("m\n");
                    if (voltage != null) response.append("  电压: ").append(voltage).append("V\n");
                }
                
                return response.toString();
                
            } else {
                // 解析失败
                String errorMsg = message.getErrorMessage();
                logger.warn("SL651报文解析失败: 原始格式={}, 错误={}", encodingFormat, errorMsg);
                return "SL651报文解析失败: " + errorMsg + "\n";
            }
            
        } catch (Exception e) {
            logger.error("SL651报文处理异常: 格式={}", encodingFormat, e);
            return "SL651报文处理异常: " + e.getMessage() + "\n";
        }
    }
    
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        logger.error("连接异常: {}", ctx.channel().remoteAddress(), cause);
        
        // 发送错误响应
        String errorMessage = "服务器内部错误\n";
        ByteBuf errorBuf = Unpooled.copiedBuffer(errorMessage, CharsetUtil.UTF_8);
        
        ChannelFuture future = ctx.writeAndFlush(errorBuf);
        future.addListener(ChannelFutureListener.CLOSE);
    }
    
    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
        if (evt instanceof io.netty.handler.timeout.IdleStateEvent) {
            io.netty.handler.timeout.IdleStateEvent idleEvent = (io.netty.handler.timeout.IdleStateEvent) evt;
            
            switch (idleEvent.state()) {
                case READER_IDLE:
                    logger.warn("读取空闲超时: {}", ctx.channel().remoteAddress());
                    break;
                case WRITER_IDLE:
                    logger.warn("写入空闲超时: {}", ctx.channel().remoteAddress());
                    break;
                case ALL_IDLE:
                    logger.warn("读写空闲超时，关闭连接: {}", ctx.channel().remoteAddress());
                    ctx.close();
                    break;
                default:
                    break;
            }
        }
        
        super.userEventTriggered(ctx, evt);
    }
    
    /**
     * 获取当前连接数（静态方法）
     */
    public static int getCurrentConnectionCount() {
        return connectionCount.get();
    }
}